package com.itzxx.huazhun.utils.ble

import android.annotation.SuppressLint
import android.app.Activity
import android.bluetooth.BluetoothGattCharacteristic
import android.text.TextUtils
import cn.com.heaton.blelibrary.ble.Ble
import cn.com.heaton.blelibrary.ble.callback.BleConnectCallback
import cn.com.heaton.blelibrary.ble.callback.BleMtuCallback
import cn.com.heaton.blelibrary.ble.callback.BleNotifyCallback
import cn.com.heaton.blelibrary.ble.callback.BleScanCallback
import cn.com.heaton.blelibrary.ble.callback.BleWriteCallback
import cn.com.heaton.blelibrary.ble.model.BleDevice
import cn.com.heaton.blelibrary.ble.model.ScanRecord
import cn.com.heaton.blelibrary.ble.queue.RequestTask
import cn.com.heaton.blelibrary.ble.utils.ByteUtils
import com.itzxx.huazhun.utils.Timer
import com.itzxx.library_base_ktx.ext.util.loge

/**
 * Desc:
 *
 * Author: zhangxiaoxiao
 * Date: 2024/7/25 18:10
 * Updater:
 * Update Time:
 * Update Comments:
 */

object BleHelper {

    @SuppressLint("StaticFieldLeak")
    private val ble: Ble<BleDevice> = Ble.getInstance()

    private var connectedBleDevice: BleDevice? = null

    private var bleConnectCallBack: BleConnectCallback<BleDevice>? = null

    private val bleListenerList = mutableListOf<BleListener>()


    private val bleDevicesMap = mutableMapOf<String, BleDevice>()

    //定时器
    private val timer = Timer()

    fun startScan() {
        ble.bleRequest
        bleDevicesMap.clear()
        ble.startScan(object : BleScanCallback<BleDevice>() {
            override fun onLeScan(device: BleDevice?, rssi: Int, scanRecord: ByteArray?) {
                device?.let {
                    synchronized(ble.locker) {
                        if (bleDevicesMap.containsKey(it.bleName)) {
                            return
                        }
                        if (!TextUtils.isEmpty(it.bleName) && it.bleName.contains("HZC-")) {
                            "onLeScan: ${it.bleName}".loge()
                            device.scanRecord = ScanRecord.parseFromBytes(
                                scanRecord
                            )
                            if (bleDevicesMap.isEmpty()) {
                                bleListenerList.forEach {
                                    it.onBleScanFirstDevice(device)
                                }
                            }
                            bleDevicesMap[device.bleName] = device
                        }
                    }
                }
            }

            override fun onStart() {
                super.onStart()
                bleDevicesMap.clear()
                bleListenerList.forEach {
                    it.startBleScan()
                }
            }

            override fun onStop() {
                super.onStop()
                "onStop".loge()
                val bleList = arrayListOf<BleDevice>()
                if (connectedBleDevice != null && bleConnectCallBack != null && !bleDevicesMap.containsKey(
                        connectedBleDevice!!.bleName
                    )
                ) {
                    disconnect()
                    connectedBleDevice = null
                    bleConnectCallBack = null
                }
                bleDevicesMap.forEach { (_, value) ->
                    bleList.add(value)
                }

                bleListenerList.forEach {
                    it.stopBleScan(bleList)
                }
            }

            override fun onScanFailed(errorCode: Int) {
                super.onScanFailed(errorCode)
                "onScanFailed: $errorCode".loge()
                bleListenerList.forEach {
                    it.onScanFailed("查找失败")
                }
            }
        })
    }

    @OptIn(ExperimentalUnsignedTypes::class)
    fun connect(bleDevice: BleDevice) {
        if (connectedBleDevice != null && bleConnectCallBack != null) {
            //选择别的设备首先先断开之前
            if (!TextUtils.equals(bleDevice.bleAddress, connectedBleDevice?.bleAddress)) {
                ble.disconnect(connectedBleDevice, bleConnectCallBack)
            }
        }
        var subpackageUByteArray: UByteArray? = null
        if (!bleDevice.isConnected) {
            bleConnectCallBack = object : BleConnectCallback<BleDevice>() {
                override fun onConnectionChanged(device: BleDevice?) {
                    device?.let {
                        "onConnectionChanged:${it.bleName}".loge()
                        val tempDevice = bleDevicesMap[it.bleName]
                        if (tempDevice != null) {
                            tempDevice.connectionState = device.connectionState
                            connectedBleDevice = tempDevice
                        }

                        if (TextUtils.equals(bleDevice.bleAddress, device.bleAddress)) {
                            bleDevice.connectionState = device.connectionState
                        }
                    }
                }

                override fun onReady(device: BleDevice?) {
                    super.onReady(device)
                    device?.run {
                        ble.setMTU(device.bleAddress, 512, object : BleMtuCallback<BleDevice>() {
                            override fun onMtuChanged(device: BleDevice?, mtu: Int, status: Int) {
                                super.onMtuChanged(device, mtu, status)
                                "onMtuChanged:mtu=${mtu}，status=${status}".loge()
                                if (status == 0) {
                                    ble.enableNotify(device,
                                        true,
                                        object : BleNotifyCallback<BleDevice>() {
                                            override fun onChanged(
                                                device: BleDevice?,
                                                characteristic: BluetoothGattCharacteristic?
                                            ) {
                                                characteristic?.let {
                                                    "收到硬件数据>>>>>onChanged:${
                                                        ByteUtils.toHexString(
                                                            it.value
                                                        )
                                                    }".loge()
                                                    timer.stop()
                                                    val receiveUByteArray = it.value.toUByteArray()
                                                    //被分包
                                                    if (dataHeaderVerification(receiveUByteArray) &&
                                                        !dataEndVerification(receiveUByteArray)
                                                    ) {
                                                        subpackageUByteArray = receiveUByteArray
                                                    } else if (dataEndVerification(receiveUByteArray)) {
                                                        subpackageUByteArray =
                                                            if (dataHeaderVerification(
                                                                    receiveUByteArray
                                                                )
                                                            ) {
                                                                receiveUByteArray
                                                            } else {
                                                                subpackageUByteArray!!.plus(
                                                                    receiveUByteArray
                                                                )
                                                            }
                                                        subpackageUByteArray?.let { subpackageIt ->
                                                            val type =
                                                                BleParseData.handleCmdTypeDResponse(
                                                                    subpackageIt
                                                                )
                                                            val response =
                                                                BleParseData.handleCoordinatorResponse(
                                                                    subpackageIt
                                                                )
                                                            "收到硬件数据>>>>>onChanged=JSON:${
                                                                response
                                                            }".loge()
                                                            bleListenerList.forEach { value ->
                                                                value.onEnableDataNotify(
                                                                    type,
                                                                    response
                                                                )
                                                            }
                                                        }

                                                    }
                                                }
                                            }

                                            override fun onNotifySuccess(device: BleDevice?) {
                                                super.onNotifySuccess(device)
                                                "设置通知成功:${device?.bleName}".loge()

                                                bleListenerList.forEach {
                                                    (device ?: connectedBleDevice)?.let { value ->
                                                        it.onNotifySuccess(
                                                            value
                                                        )
                                                    }
                                                }
                                            }
                                        })
                                }
                            }
                        })
                    }
                }

                override fun onConnectCancel(device: BleDevice?) {
                    super.onConnectCancel(device)
                    device?.let {
                        "onConnectionChanged:${it.bleName}".loge()
                        val tempDevice = bleDevicesMap[it.bleName]
                        if (tempDevice != null) {
                            tempDevice.connectionState = device.connectionState
                        }

                        if (TextUtils.equals(bleDevice.bleAddress, device.bleAddress)) {
                            bleDevice.connectionState = device.connectionState
                        }
                    }
                }

                override fun onConnectFailed(device: BleDevice?, errorCode: Int) {
                    super.onConnectFailed(device, errorCode)
                    device?.let {
                        "onConnectFailed:${it.bleName}".loge()
                        if (TextUtils.equals(bleDevice.bleAddress, device.bleAddress)) {
                            bleDevice.connectionState = device.connectionState
                        }
                    }
                    bleListenerList.forEach { value ->
                        value.onConnectFail("设备连接失败")
                    }
                }
            }
            ble.connect(bleDevice.bleAddress, bleConnectCallBack)
        }
    }

    fun disconnect() {
        if (connectedBleDevice != null && bleConnectCallBack != null) {
            ble.disconnect(connectedBleDevice, bleConnectCallBack)
        }
    }

    fun isConnected(): Boolean {
        return connectedBleDevice?.isConnected ?: false
    }

    fun write(byteArray: ByteArray) {
        "发送：${byteArray.joinToString(separator = ":") { "%02x".format(it) }}".loge()
        if (connectedBleDevice != null && bleConnectCallBack != null) {
            ble.write(connectedBleDevice, byteArray, object : BleWriteCallback<BleDevice>() {
                override fun onWriteSuccess(
                    device: BleDevice?, characteristic: BluetoothGattCharacteristic?
                ) {
                    "onWriteSuccess:${characteristic}".loge()
                }

                override fun onWriteFailed(device: BleDevice?, failedCode: Int) {
                    super.onWriteFailed(device, failedCode)
                    "onWriteFailed:$failedCode".loge()
                }
            })
        }
    }

    fun writeRetryWhen(byteArray: ByteArray, num : Int,listener: BleWriteListener) {
        "发送writeRetryWhen：${byteArray.joinToString(separator = ":") { "%02x".format(it) }}".loge()
        if (connectedBleDevice != null && bleConnectCallBack != null) {
            var tempNum = 0
            ble.writeQueue(
                RequestTask.Builder().devices(connectedBleDevice).data(byteArray).delay(100)
                    .build()
            )
            //做检查任务
            timer.start(1000L){
                if (tempNum > num) {
                    listener.onWriteFail()
                    timer.stop()
                    return@start
                }
                ble.writeQueue(
                    RequestTask.Builder().devices(connectedBleDevice).data(byteArray).delay(100)
                        .build()
                )
                tempNum = tempNum.plus(1)
            }
        }
    }

    fun writeDelay(byteArray: ByteArray) {
        "发送：${byteArray.joinToString(separator = ":") { "%02x".format(it) }}".loge()
        if (connectedBleDevice != null && bleConnectCallBack != null) {
            ble.writeQueue(
                RequestTask.Builder().devices(connectedBleDevice).data(byteArray).delay(30)
                    .build()
            )
        }
    }

    fun writeDelay(time: Long, byteArray: ByteArray) {
        "发送：${byteArray.joinToString(separator = ":") { "%02x".format(it) }}".loge()
        if (connectedBleDevice != null && bleConnectCallBack != null) {
            ble.writeQueue(
                RequestTask.Builder().devices(connectedBleDevice).data(byteArray).delay(time)
                    .build()
            )
        }
    }

    fun getConnectBleDevice(): BleDevice? {
        return if (connectedBleDevice != null) {
            connectedBleDevice
        } else {
            null
        }
    }

    fun initConnectBleDevicee(bleDevice: BleDevice?) {
        connectedBleDevice = bleDevice
    }

    //添加设备监听
    fun addBleListener(listener: BleListener) {
        bleListenerList.add(listener)
    }

    //移除设备监听
    fun removeBleListener(listener: BleListener) {
        bleListenerList.remove(listener)
    }

    //获取所以设备
    fun getBleBaseDevices(): List<BleDevice> {
        val bleList = arrayListOf<BleDevice>()
        bleDevicesMap.forEach { (_, value) ->
            bleList.add(value)
        }
        return bleList
    }

    /**
     * 是否打开权限
     * @param activity Activity
     */
    fun isBleEnable(activity: Activity): Boolean {
        //如果未打开蓝牙主动打开一下
        ble.turnOnBlueTooth(activity)
        return ble.isBleEnable
    }

    fun released() {
        ble.released();
    }
}